package com.tutu.common.util;

import java.beans.PropertyDescriptor;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.ConvertUtilsBean;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.beanutils.converters.DateConverter;
import org.apache.commons.beanutils.converters.LongConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;

public class BeanUtils {
	
	protected final static Logger logger = LoggerFactory.getLogger(BeanUtils.class);
	
	public static ConvertUtilsBean convertUtilsBean = new ConvertUtilsBean();
	static{
		convertUtilsBean.register(new DateConverter(), Date.class);
		convertUtilsBean.register(new LongConverter(null), Long.class);
	}
	private static BeanUtilsBean beanUtilsBean = new BeanUtilsBean(convertUtilsBean, new PropertyUtilsBean());
	
	public static boolean isInherit(Class cls, Class parentClass){
		return parentClass.isAssignableFrom(cls);
	}
	public static void populateEntity(Object entity,Map map){
		try{
			beanUtilsBean.populate(entity, map);
		}catch(Exception e){
			ReflectionUtils.handleReflectionException(e);
		}
	}
	public static Object cloneBean(Object bean){
		try{
			return beanUtilsBean.cloneBean(bean);
		}catch(Exception e){
			ReflectionUtils.handleReflectionException(e);
		}
		return null;
	}
	public static void copyNotNullProperties(Object dest, Object orig){
		if (dest == null||orig == null) {
			return;
		}
		try{
		if ((orig instanceof DynaBean)) {
			DynaProperty[] origDescriptors = ((DynaBean)orig).getDynaClass().getDynaProperties();
			for (int i = 0; i < origDescriptors.length; i++) {
				String name = origDescriptors[i].getName();
				if ((beanUtilsBean.getPropertyUtils().isReadable(orig, name)) && (beanUtilsBean.getPropertyUtils().isWriteable(dest, name))){
					Object value = ((DynaBean)orig).get(name);
					beanUtilsBean.copyProperty(dest, name, value);
				}
			}
		} else if ((orig instanceof Map)) {
			Iterator entries = ((Map)orig).entrySet().iterator();
			while (entries.hasNext()) {
				Map.Entry entry = (Map.Entry)entries.next();
				String name = (String)entry.getKey();
				if (beanUtilsBean.getPropertyUtils().isWriteable(dest, name)) {
					beanUtilsBean.copyProperty(dest, name, entry.getValue());
				}
			}
		} else {
			PropertyDescriptor[] origDescriptors = beanUtilsBean.getPropertyUtils().getPropertyDescriptors(orig);
			for (int i = 0; i < origDescriptors.length; i++) {
				String name = origDescriptors[i].getName();
				if (!"class".equals(name)){
					if ((beanUtilsBean.getPropertyUtils().isReadable(orig, name)) && (beanUtilsBean.getPropertyUtils().isWriteable(dest, name)))
						try{
							Object value = beanUtilsBean.getPropertyUtils().getSimpleProperty(orig, name);
							if (value != null) {
								beanUtilsBean.copyProperty(dest, name, value);
							}
						} catch (NoSuchMethodException e) {
							logger.debug("copyProperty", e);
						}
				}
			}
		}
		} catch (Exception ex) {
			ReflectionUtils.handleReflectionException(ex);
		}
	}
	
	public static <T> T copyProperties(Class<T> destClass, Object orig){
		T target = null;
		try{
			target = destClass.newInstance();
			copyProperties(target, orig);
		}catch(Exception e){
			ReflectionUtils.handleReflectionException(e);
		}
		return target;
	}
	public static void copyProperties(Object dest, Object orig){
		try{
			beanUtilsBean.copyProperties(dest, orig);
		}catch(Exception e){
			ReflectionUtils.handleReflectionException(e);
		}
	}
	public static void copyProperty(Object bean, String name, Object value){
		try{
			beanUtilsBean.copyProperty(bean, name, value);
		}catch(Exception e){
			ReflectionUtils.handleReflectionException(e);
		}
	}
	public static Map describe(Object bean){
		try{
			return beanUtilsBean.describe(bean);
		}catch(Exception e){
			ReflectionUtils.handleReflectionException(e);
		}
		return null;
	}
	public static String[] getArrayProperty(Object bean, String name){
		try{
			return beanUtilsBean.getArrayProperty(bean, name);
		}catch(Exception e){
			ReflectionUtils.handleReflectionException(e);
		}
		return null;
	}
	public static String getIndexedProperty(Object bean, String name, int index){
		try{
			return beanUtilsBean.getIndexedProperty(bean, name, index);
		}catch(Exception e){
			ReflectionUtils.handleReflectionException(e);
		}
		return null;
	}
	public static String getIndexedProperty(Object bean, String name){
		try{
			return beanUtilsBean.getIndexedProperty(bean, name);
		}catch(Exception e){
			ReflectionUtils.handleReflectionException(e);
		}
		return null;
	}
	public static String getMappedProperty(Object bean, String name, String key){
		try{
			return beanUtilsBean.getMappedProperty(bean, name, key);
		}catch(Exception e){
			ReflectionUtils.handleReflectionException(e);
		}
		return null;
	}
	public static String getMappedProperty(Object bean, String name){
		try{
			return beanUtilsBean.getMappedProperty(bean, name);
		}catch(Exception e){
			ReflectionUtils.handleReflectionException(e);
		}
		return null;
	}
	public static String getNestedProperty(Object bean, String name){
		try{
			return beanUtilsBean.getNestedProperty(bean, name);
		}catch(Exception e){
			ReflectionUtils.handleReflectionException(e);
		}
		return null;
	}
	public static String getProperty(Object bean, String name){
		try{
			return beanUtilsBean.getProperty(bean, name);
		}catch(Exception e){
			ReflectionUtils.handleReflectionException(e);
		}
		return null;
	}
	public static PropertyUtilsBean getPropertyUtils(){
		try{
			return beanUtilsBean.getPropertyUtils();
		}catch(Exception e){
			ReflectionUtils.handleReflectionException(e);
		}
		return null;
	}
	public static String getSimpleProperty(Object bean, String name){
		try{
			return beanUtilsBean.getSimpleProperty(bean, name);
		}catch(Exception e){
			ReflectionUtils.handleReflectionException(e);
		}
		return null;
	}
	public static void populate(Object bean, Map properties){
		try{
			beanUtilsBean.populate(bean, properties);
		}catch(Exception e){
			ReflectionUtils.handleReflectionException(e);
		}
	}
	public static void setProperty(Object bean, String name, Object value){
		try{
			beanUtilsBean.setProperty(bean, name, value);
		}catch(Exception e){
			ReflectionUtils.handleReflectionException(e);
		}
	}
}
